// Loesung_von_Aufgabe_7.6_2_Spiegel

// Zeigerformalismus für den Spiegel
// Damit hier ein Spiegel simuliert wird, sind nur zwei Änderungen in der setup()-funktion notwending
// Der Einzelspalt fungiert so als Spiegel
// --------------------------------------------------------------------------------------------------


// Zuerst werden die Variablen definiert. Einige davon als Vektor, da wir, wie im Text erwähnt, auch vektoriell rechnen müssen
PVector Q; // Ortsvektor der Quelle der Quantenobjekte
PVector E; // Ortsvektor des Empfängers
PVector M; // M ist der Vektor, der auf die Spaltöffnung zeigt
PVector PfadResultierend = new PVector(0, 0); /* Vektorsumme der Pfeile von allen berücksichtigen Wege zwischen der feststehenden 
 Quelle Q und dem feststehenden Empfänger E */
float EinzelspaltX = 250; // Lage des Einzelspaltes
float EinzelspaltBreite = 50;
float Wellenlaenge = 10;
float PfadAbstand = 1; // Abstand der Pfade in der Spaltöffnung in Pixel
boolean AufbauNeuZeichnen = false; // Die Variable AufbauNeuZeichnen vom Typ boolean wird deklariert

void AufbauZeichnen()
{
  background(230, 230, 230);

  // Die Elemente des Aufbaus werden flexible initialisiert, sodass er sich bei Änderung der obigen Variablen automatisch anpassen
  strokeWeight(1);
  stroke(0);
  line(Q.x, height / 2, E.x, height / 2); // Mittellinie
  fill(255);
  rect(E.x, 0, 5, height); // Schirm hinter dem Empfänger
  noStroke();
  fill(255, 0, 0);
  ellipse(Q.x, Q.y, 10, 10); // Quelle
  fill(0, 255, 0);
  ellipse(E.x, E.y, 10, 10); // Empfänger
  fill(0);
  rect(EinzelspaltX - 2.5, 0, 5, (height - EinzelspaltBreite) / 2); // Obere Blende des Einzelspaltes
  rect(EinzelspaltX - 2.5, height - (height - EinzelspaltBreite) / 2, 5, (height - EinzelspaltBreite) / 2); // Untere Blende des Einzelspaltes
}

void setup()
{
  size(1000, 500);

  // Initialisierung der oben definierten Vektoren
  Q = new PVector(50, height / 3); // Lage der Quelle --------- Etwas nach oben verschoben, damit Reflexion simuliert wird
  E = new PVector(50, height / 2); // Lage des Empfängers ----- Der Empfänger wurde auf die Seite der Quelle verschoben, damit die reflektierten Strahlen 'empfangen' werden

  M = new PVector(EinzelspaltX, (height - EinzelspaltBreite) / 2); // Die Spitze des M-Vektors liegt zuerst an der Oberseite der Spaltöffnung

  AufbauZeichnen();
}

void mousePressed() // Die mousePressed()-Funktion wird aufgerufen, wenn eine Maustaste gedrückt ist
{
  E.y = mouseY; // Der Empfänger nimmt bei gedrückter Maustaste den y-Wert des Mauszeigers an
  M.y = (height - EinzelspaltBreite) / 2; 
  PfadResultierend.set(0, 0); /* Setzt das Programm auf den Startwert zurück. D.h., für jede Stellung des Empfängers kann die PfadResultierende bei 
   null beginnend neuberechnet werden */
  loop(); // Die draw()-Funktion wird wieder durchlaufen
  AufbauNeuZeichnen = true; // Der Versuchsaufbau wird beim nächsten Aufruf der draw()-Funktion neu gezeichnet
}

void mouseDragged() // Die mouseDragged()-Funktion wird aufgerufen, wenn eine Maustaste gedrückt ist und sich die Maus bewegt
{
  E.y = mouseY;
  M.y = (height - EinzelspaltBreite) / 2; // Setzt das Programm auf die Startwerte zurück
  PfadResultierend.set(0, 0); /* Setzt das Programm auf den Startwert zurück. D.h., für jede Stellung des Empfängers kann die PfadResultierende bei 
   null beginnend neuberechnet werden */
  loop(); // Die draw()-Funktion wird wieder durchlaufen
  AufbauNeuZeichnen = true; // Der Versuchsaufbau wird beim nächsten Aufruf der draw()-Funktion neu gezeichnet
}

void draw()
{ 
  if (AufbauNeuZeichnen == true)
  {
    AufbauZeichnen(); // Der Aufbau wird gezeichnet
    AufbauNeuZeichnen = false; // Die Aufbauzeichnung wird nun nicht mehr neu gezeichnet
  }

  while (true) // while()-Schleife
  {
    stroke(0, 0, 255);
    line(Q.x, Q.y, M.x, M.y); // Linie von der Quelle zur Spaltmitte
    line(M.x, M.y, E.x, E.y); // Linie von der Spaltmitte zum Empfänger 

    float PfadLaenge = Q.dist(M) + M.dist(E); // Die Pfadlänge wird berechnet
    float Phase = PfadLaenge / Wellenlaenge; // Die Phase (Winkel) wird berechnet
    PVector PfadVektor = new PVector(cos(Phase * 2 * PI) * 10, sin(Phase * 2 * PI) * 10); // Am Anfang (Pfadlänge = 0) liegt der Zeiger auf der Rechtswertachse

    stroke(0, 200, 0);
    // Nun werden die einzelnen Pfadvektoren (grün) gezeichnet. Beginnend am Anfang der Pfadresultierenden.
    line(PfadResultierend.x + 600, PfadResultierend.y + 100, PfadResultierend.x + PfadVektor.x + 600, PfadResultierend.y + PfadVektor.y + 100);

    PfadResultierend.add(PfadVektor); // Die grünen Pfadvektoren werden aneinander gereiht
    M.y += PfadAbstand; // Der Abstand der einzelnen Pfade wird um den PfadAbstand so lange erhöht bis die untere Spaltblende erreicht ist

    if (M.y > height - (height - EinzelspaltBreite) / 2)
    {
      strokeWeight(3);
      stroke(255, 0, 0);
      line(600, 100, 600 + PfadResultierend.x, 100 + PfadResultierend.y); // Die Resultierende wir gezeichnet
      noStroke();
      noLoop(); // Schleifendurchlauf wird gestoppt
      println(E.y, ",", PfadResultierend.mag() * PfadResultierend.mag()); /* Die Werte für die Lage des Empfängers und für das Quadrat der PfadResultierenden
       werden in die Konsole geschrieben */
      break; // Nun wird die while-Schleife verlassen
    }
  }
}